/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.analysismodel;

import java.text.DecimalFormat;
import java.util.ListIterator;

import br.ufmg.dees.insane.crossSection.CrossSection;
import br.ufmg.dees.insane.materialMedia.material.LinearElasticIsotropic;
import br.ufmg.dees.insane.model.disc.element.FrameElement;
import br.ufmg.dees.insane.model.disc.element.force.ElementForce;
import br.ufmg.dees.insane.model.disc.fem.FemModel;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.model.disc.pointforce.PointForce;
import br.ufmg.dees.insane.model.disc.shape.Shape1DCart;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;


/**
*A class representing the analysis model of a plane truss element.<p>
*
*The local Z axis of a plane truss element is parallel to the global Z axis, with the same direction.<br>
*The local Y axis of a plane truss element is perpendicular to the local X axis (initial node - final node direction) and to the local Z axis.<br>
*
*@author Fonseca, Flavio & Pitangueira, Roque
*@version 1.0
*@since September 2003
*@see model.discrete.element.FrameElement
*/


public class PlaneTruss extends FrameElmAnalysis {
	
	private static final long serialVersionUID = 1L;

	/** Constructs a PlaneTruss analysis model, sets its ndf to 2 and its valid equations to true in the positions 0 and 1.*/
	public PlaneTruss() {
		type = "PlaneTruss";
		ndf = 2;
		validEquations[0] = true;
		validEquations[1] = true;
		validEquations[2] = false;
		validEquations[3] = false;
		validEquations[4] = false;
		validEquations[5] = false;
		dominion = 1;
	};

//********************************************************************************
	
	/** Returns the type of the Shape adequate to this type of AnalysisModel.
	*@return The type of the Shape adequate to this type of AnalysisModel.
	*/
	public String getDefaultShapeType() {
		return ("Linear1DCart");
	}
	
//********************************************************************************
	
	/** Returns the nodal rotation matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*@param elm The FrameElement whose nodal rotation matrix is desired.
	*@return The nodal rotation matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix nodalRotationMatrix(FrameElement elm) {
		IMatrix mat = new IMatrix(4,4);
		double ia = elm.getInitialNode().getAngle() * Math.PI / 180;
		double fa = elm.getFinalNode().getAngle() * Math.PI / 180;
		mat.setElement(0, 0, Math.cos(ia));
		mat.setElement(0, 1, Math.sin(ia));
		mat.setElement(1, 0, -Math.sin(ia));
		mat.setElement(1, 1, Math.cos(ia));
		mat.setElement(2, 2, Math.cos(fa));
		mat.setElement(2, 3, Math.sin(fa));
		mat.setElement(3, 2, -Math.sin(fa));
		mat.setElement(3, 3, Math.cos(fa));
		return (mat);
	};
	
//********************************************************************************
	
	/** Returns the local stiffness matrix of the specified FrameElement, accordingly to this AnalysisModel type.<br>
	*This matrix does not consider the possible liberations at the extremities of the FrameElement.
	*@param elm The FrameElement whose local stiffness matrix is desired.
	*@return The local stiffness matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix localStiffnessMatrix(FrameElement elm){
		IMatrix mat = new IMatrix(4,4);
		mat.setZero();
		LinearElasticIsotropic elmMaterial = (LinearElasticIsotropic) elm.getMaterial();
		CrossSection elmCrossSection = elm.getCrossSection();
		
		//Setting the value of factor = (A*E/L)
		double factor = elmCrossSection.getArea() * elmMaterial.getMaterialValues(elmMaterial.ELASTICITY).doubleValue() / elm.getLength();
		
		//Setting the value of the matrix
		mat.setElement(0, 0, factor);
		mat.setElement(0, 2, -factor);
		mat.setElement(2, 0, -factor);
		mat.setElement(2, 2, factor);
		
		return (mat);
		
	};
	
//********************************************************************************
	
	/** Returns the corrected local stiffness matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*This matrix is the same matrix calculated in the localStiffnessMatrix() method, because there is no liberation at extremities in a truss.
	*@param elm The FrameElement whose corrected local stiffness matrix is desired.
	*@return The corrected local stiffness matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix localCorrectedStiffnessMatrix(FrameElement elm) {
		
		//There is no liberation at extremities in a Plane Truss
		IMatrix mat = new IMatrix(4, 4);
		mat = localStiffnessMatrix(elm);
		return (mat);
		
	};
	
//********************************************************************************
	
	/** Returns the transformation matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*@param elm The FrameElement whose transformation matrix is desired.
	*@return The transformation matrix of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix transformationMatrix(FrameElement elm){
		IMatrix mat = new IMatrix(4,4);
		mat.setZero();
		Node elmInitialNode = elm.getInitialNode();
		Node elmFinalNode = elm.getFinalNode();
		
		//Setting the value of cos
		double cos = (elmFinalNode.getCoord().x - elmInitialNode.getCoord().x) / elm.getLength(); 
		
		//Setting the value of sen
		double sen = (elmFinalNode.getCoord().y - elmInitialNode.getCoord().y) / elm.getLength();
		
		//Setting the value of the matrix
		mat.setElement(0, 0, cos);
		mat.setElement(0, 1, sen);
		mat.setElement(1, 0, -sen);
		mat.setElement(1, 1, cos);
		mat.setElement(2, 2, cos);
		mat.setElement(2, 3, sen);
		mat.setElement(3, 2, -sen);
		mat.setElement(3, 3, cos);
		
		return (mat);
	};
	
//********************************************************************************
	
	/** Mounts the shape function matrix accordingly to this AnalysisModel type with the values of two IVectors.<br>
	*The first IVector must contain the shape functions values which will be put in the upper part of the matrix.<br>
	*The second IVector must contain the shape functions values which will be put in the lower part of the matrix (related to the derivated shape functions).
	*@param n1 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@param n2 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@return The shape function matrix accordingly to this AnalysisModel type.
	*/
	public IMatrix mountMatrixN(IVector n1, IVector n2) {
		IMatrix n = new IMatrix(2, 4);
		n.setZero();
		n.setElement(0, 0, n1.getElement(0));
		n.setElement(1, 1, n1.getElement(0));
		n.setElement(0, 2, n1.getElement(1));
		n.setElement(1, 3, n1.getElement(1));
		return (n);
	};
	
//********************************************************************************
	
	/** Mounts the shape function matrix accordingly to this AnalysisModel type with the values of one IVector.<br>
	*The IVector must contain the shape functions values which will be put in the upper part of the matrix.<br>
	*The value zero will be put in the lower part of the matrix (related to the derivated shape functions).
	*@param n1 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@return The shape function matrix accordingly to this AnalysisModel type.
	*/
	public IMatrix mountMatrixN(IVector n1) {
		IMatrix n = new IMatrix(2, 4);
		n.setZero();
		n.setElement(0, 0, n1.getElement(0));
		n.setElement(1, 1, n1.getElement(0));
		n.setElement(0, 2, n1.getElement(1));
		n.setElement(1, 3, n1.getElement(1));
		return (n);
	};
    

    /** Returns the B matrix related to analysis model type 
    *@param dg The vector containing global derivates of shape functions.
    *@return The matrix B 
    */
    public IMatrix mountBMatrix(IVector dg) {       
        IMatrix b = new IMatrix(1,4);
        b.setZero();
        b.setElement(0,0,dg.getElement(0));
        b.setElement(0,2,dg.getElement(1));
        return(b);
    };
	
    
    /** Mounts the matrix of the material properties for the analysis model type.
     *@param a The matrix of material properties.
     *@return matrix D related to analysis model type 
     */
     public IMatrix mountDMatrix(double[][] a, CrossSection cs) {
         IMatrix d = new IMatrix(1,1);
         d.setElement(0,0,a[0][0]*cs.getArea());
         return d;
     };
//********************************************************************************
	
	/** Returns the local equivalent nodal force vector of the specified FrameElement, accordingly to this AnalysisModel type.
	*This vector does not consider the possible liberations at the extremities of the FrameElement.
	*@param elm The FrameElement whose local equivalent nodal force vector is desired.
	*@return The local equivalent nodal force vector of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IVector localEquivalentForceVector(FrameElement elm) {
		IVector lEqForce = new IVector(4);
		IVector a = new IVector(2);
		IVector b = new IVector(2);
		IVector v1;
		IVector v2;
		IVector f1 = new IVector(4);
		IVector f2 = new IVector(4);
		IMatrix n;
		IMatrix n1;
		IMatrix n2;
		Shape1DCart shp = (Shape1DCart) elm.getShape();
		
		//Calculating equivalent forces for elmPointForces
		PointForce elmPF;
		ListIterator elmPFs = elm.getElmPointForcesList().listIterator();
		while (elmPFs.hasNext()) {
			elmPF = (PointForce) elmPFs.next();
			
			//Setting the values for a vector (fe = N * a)
			a.setElement(0, elmPF.getForce(0));
			a.setElement(1, elmPF.getForce(1));
			
			v1 = shp.getShapeFunction(elm, elmPF.getCoord().x);
			n = mountMatrixN(v1);
			n.transpose();
			f1.mul(n, a);
			lEqForce.add(f1);
		};
		
		//Calculating equivalent forces for elementForces
		a.zero();
		ElementForce bf;
		PointForce pf1;
		PointForce pf2;
		ListIterator bfs = elm.getElmLineForcesList().listIterator();
		while (bfs.hasNext()) {
			bf = (ElementForce) bfs.next();
			pf1 = (PointForce) bf.getPointForcesList().get(0);
			pf2 = (PointForce) bf.getPointForcesList().get(1);
			
			pf1 = (PointForce) bf.getPointForcesList().get(0);
			pf2 = (PointForce) bf.getPointForcesList().get(1);
			//Setting the values of the vectors a and b (lEFV = IntegratedShapeFunctionMultX * a + IntegratedShapeFunction * b)
			a.setElement(0, (pf2.getForce(0) - pf1.getForce(0)) / (pf2.getCoord().x - pf1.getCoord().x));
			a.setElement(1, (pf2.getForce(1) - pf1.getForce(1)) / (pf2.getCoord().x - pf1.getCoord().x));
			b.setElement(0, -(a.getElement(0)) * pf2.getCoord().x + pf2.getForce(0));
			b.setElement(1, -(a.getElement(1)) * pf2.getCoord().x + pf2.getForce(1));
			
			v1 = shp.getIntegratedShapeFunctionMultX(elm, pf1.getCoord().x, pf2.getCoord().x);
			v2 = shp.getIntegratedShapeFunction(elm, pf1.getCoord().x, pf2.getCoord().x);
			n1 = mountMatrixN(v1);
			n2 = mountMatrixN(v2);
			n1.transpose();
			n2.transpose();
			f1.mul(n1, a);
			f2.mul(n2, b);
			f1.add(f2);
			lEqForce.add(f1);
		};
		
		//Calculating equivalent forces for temperature changes
		f1.zero();
		LinearElasticIsotropic mat = (LinearElasticIsotropic) elm.getMaterial();
		double factor = mat.getMaterialValues(mat.ELASTICITY).doubleValue() * mat.getMaterialValues(mat.THERMAL_COEFF).doubleValue() * elm.getCrossSection().getArea() * elm.getDeltaTemp(1);
		f1.setElement(0, -factor);
		f1.setElement(2, factor);
		lEqForce.add(f1);
		
		//Calculating equivalent forces for prescribed displacements on elements
		f1.zero();
		n1 = localCorrectedStiffnessMatrix(elm);
		v1 = elm.getElmPreDisplacement();
		f2.zero();
		int j = 0;
		for (int i=0; i<6; i++) {
			if (validEquations[i]) {
				f2.setElement(j, v1.getElement(i));
				f2.setElement(j+2, v1.getElement(i+6));
				j++;
			};
		};
		f1.mul(n1, f2);
		lEqForce.add(f1);
		
		//Adding initial nodal force
		f1.setElement(0, elm.getInitialNodalForce(0));
		f1.setElement(1, elm.getInitialNodalForce(1));
		f1.setElement(2, elm.getInitialNodalForce(6));
		f1.setElement(3, elm.getInitialNodalForce(7));
		lEqForce.add(f1);
		
		return (lEqForce);
	};
	
//********************************************************************************
	
	/** Returns the corrected local equivalent nodal force vector of the specified FrameElement, accordingly to this AnalysisModel type.
	*This vector is the same vector calculated in the localEquivalentForceVector() method, because there is no liberation at extremities in a truss.
	*@param elm The FrameElement whose corrected local equivalent nodal force vector is desired.
	*@return The corrected local equivalent nodal force vector of the specified FrameElement, accordingly to this AnalysisModel type.
	*/
	public IVector localCorrectedEquivalentForceVector(FrameElement elm) {
		
		//There is no liberation at extremities in a Plane Truss
		return (localEquivalentForceVector(elm));
		
	};
	
//********************************************************************************
	
	/** Prints in the screen a table with the valid nodal displacements for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printDisplacements(FemModel mod) {
		DecimalFormat fmt = new DecimalFormat();
		fmt.applyPattern("0.000E00");
		Node node;
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("NODE DISPLACEMENTS:");
		System.out.println("Node" +"\t"+ "Dx" +"\t\t"+ "Dy");
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			System.out.println("Node " + node.getLabel() +"\t"+ fmt.format(node.getDisplacement(0)) +"\t\t"+ fmt.format(node.getDisplacement(1)));
		};
		System.out.println("\t");
	};
	
//********************************************************************************
	
	/** Prints in the screen a table with the valid actions at elements' extremities for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printActionsAtExtremities(FemModel mod) {
		DecimalFormat fmt = new DecimalFormat();
		fmt.applyPattern("####0.000");
		System.out.println("ACTIONS AT ELEMENTS' EXTREMITIES:");
		FrameElement elm;
		ListIterator elms = mod.getElementsList().listIterator();
		System.out.println("\t|------- INITIAL NODE -------|" + "\t\t|-------- FINAL NODE --------|");
		System.out.println("Elm" +"\t"+ "Fx" +"\t\t"+ "Fy" +"\t\t"+ "Fx" +"\t\t"+ "Fy");
		while (elms.hasNext()) {
			elm = (FrameElement) elms.next();
			System.out.println("Elm " + elm.getLabel() +"\t"+ fmt.format(elm.getActionAtExtremity(0)) +"\t\t"+ fmt.format(elm.getActionAtExtremity(1)) +"\t\t"+ fmt.format(elm.getActionAtExtremity(6)) +"\t\t"+ fmt.format(elm.getActionAtExtremity(7)));
		};
		System.out.println("\t");
	};
	
//********************************************************************************
	
	/** Prints in the screen a table with the valid support reactions for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public  void printReactions(FemModel mod) {
		DecimalFormat fmt = new DecimalFormat();
		fmt.applyPattern("####0.000");
		Node node;
		
		//Forces on inelastic supports
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("REACTIONS ON INELASTIC SUPPORTS:");
		System.out.println("Node" +"\t"+ "Fx" +"\t\t"+ "Fy");
		boolean anyRestraint = false;
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			boolean hasRestraint = false;
			for (int i=0; i<6; i++)
				if (node.getRestraint(i)) {
					hasRestraint = true;
					anyRestraint = true;
				};
			if (hasRestraint)
				System.out.println("Node " + node.getLabel() +"\t"+ fmt.format(node.getReaction(0)) +"\t\t"+ fmt.format(node.getReaction(1)));
		};
		if (!anyRestraint)
			System.out.println("THERE IS NO INELASTIC SUPPORT.");
		System.out.println("\t");
		
		//Forces on elastic supports
		nodes = mod.getNodesList().listIterator();
		System.out.println("REACTIONS ON ELASTIC SUPPORTS:");
		System.out.println("Node" +"\t"+ "Fx" +"\t\t"+ "Fy");
		boolean anySpring = false;
		while (nodes.hasNext()) {
			node = (Node) nodes.next();
			boolean hasSpring = false;
			double[] eReac = new double[6];
			for (int i=0; i<6; i++)
			if (node.getSpring(i)!=0) {
				hasSpring = true;
				anySpring = true;
				eReac[i] = - node.getDisplacement(i) * node.getSpring(i);
			};
			if (hasSpring)
				System.out.println("Node " + node.getLabel() +"\t"+ fmt.format(eReac[0]) +"\t\t"+ fmt.format(eReac[1]));
		};
		if (!anySpring)
			System.out.println("THERE IS NO ELASTIC SUPPORT.");
		System.out.println("\t");
	};
	
//********************************************************************************
}
